// #ifndef __SRC_UTILS_MEMPOLL_H__
// #define __SRC_UTILS_MEMPOLL_H__

#include <boost/pool/object_pool.hpp>
#include <iostream>

// #include "mempool.h"

class Demo {
  
  public:
    int a, b;

    Demo(int x = 1, int y = 2) : a(x), b(y) {};

};

template <typename T, size_t BlockSize>
inline typename MemoryPool<T, BlockSize>::size_type
MemoryPool<T, BlockSize>::padPointer(data_pointer_ p, size_type align) const noexcept {
  uintptr_t result = reinterpret_cast<uintptr_t>(p);
  return ((align - result) % align);
}

// template <typename T, size_t BlockSize>
// MemoryPool<T, BlockSize>::MemoryPool() noexcept {
//   currentBlock_ = nullptr;
//   currentSlot_ = nullptr;
//   lastSlot_ = nullptr;
//   freeSlots_ = nullptr;
// }

// template <typename T, size_t BlockSize>
// MemoryPool<T, BlockSize>::MemoryPool(const MemoryPool &memoryPool) noexcept : MemoryPool() {
// }

// template <typename T, size_t BlockSize>
// MemoryPool<T, BlockSize>::MemoryPool(MemoryPool &&memoryPool) noexcept {
//   currentBlock_ = memoryPool.currentBlock_;
//   memoryPool.currentBlock_ = nullptr;
//   currentSlot_ = memoryPool.currentSlot_;
//   lastSlot_ = memoryPool.lastSlot_;
//   freeSlots_ = memoryPool.freeSlots;
// }

// template <typename T, size_t BlockSize>
// template <class U>
// MemoryPool<T, BlockSize>::MemoryPool(const MemoryPool<U> &memoryPool) noexcept : MemoryPool() {
// }

// template <typename T, size_t BlockSize>
// MemoryPool<T, BlockSize> &
// MemoryPool<T, BlockSize>::operator=(MemoryPool &&memoryPool) noexcept {
//   if (this != &memoryPool) {
//     std::swap(currentBlock_, memoryPool.currentBlock_);
//     currentSlot_ = memoryPool.currentSlot_;
//     lastSlot_ = memoryPool.lastSlot_;
//     freeSlots_ = memoryPool.freeSlots;
//   }

//   return *this;
// }

// template <typename T, size_t BlockSize>
// MemoryPool<T, BlockSize>::~MemoryPool() noexcept {
//   slot_pointer_ curr = currentBlock_;
//   while (curr != nullptr) {
//     slot_pointer_ prev = curr->next;
//     operator delete(reinterpret_cast<void *>(curr));
//     curr = prev;
//   }
// }

// template <typename T, size_t BlockSize>
// inline typename MemoryPool<T, BlockSize>::pointer
// MemoryPool<T, BlockSize>::address(reference x) const noexcept {
//   return &x;
// }

// template <typename T, size_t BlockSize>
// inline typename MemoryPool<T, BlockSize>::const_pointer
// MemoryPool<T, BlockSize>::address(const_reference x) const noexcept {
//   return &x;
// }

// template <typename T, size_t BlockSize>
// void MemoryPool<T, BlockSize>::allocateBlock() {
//   // Allocate space for the new block and store a pointer to the previous one
//   data_pointer_ newBlock = reinterpret_cast<data_pointer_>(operator new(BlockSize));

//   reinterpret_cast<slot_pointer_>(newBlock)->next = currentBlock_;

//   currentBlock_ = reinterpret_cast<slot_pointer_>(newBlock);
//   // Pad block body to staisfy the alignment requirements for elements
//   data_pointer_ body = newBlock + sizeof(slot_pointer_);

//   size_type bodyPadding = padPointer(body, alignof(slot_type_));
//   currentSlot_ = reinterpret_cast<slot_pointer_>(body + bodyPadding);

//   lastSlot_ = reinterpret_cast<slot_pointer_>(newBlock + BlockSize - sizeof(slot_type_) + 1);
// }

// template <typename T, size_t BlockSize>
// inline typename MemoryPool<T, BlockSize>::pointer
// MemoryPool<T, BlockSize>::allocate(size_type n, const_pointer hint) {
//   if (freeSlots_ != nullptr) {
//     pointer result = reinterpret_cast<pointer>(freeSlots_);
//     freeSlots_ = freeSlots_->next;
//     return result;
//   } else {
//     if (currentSlot_ >= lastSlot_)
//       allocateBlock();
//     return reinterpret_cast<pointer>(currentSlot_++);
//   }
// }

// template <typename T, size_t BlockSize>
// inline void
// MemoryPool<T, BlockSize>::deallocate(pointer p, size_type n) {
//   if (p != nullptr) {
//     reinterpret_cast<slot_pointer_>(p)->next = freeSlots_;
//     freeSlots_ = reinterpret_cast<slot_pointer_>(p);
//   }
// }

// template <typename T, size_t BlockSize>
// inline typename MemoryPool<T, BlockSize>::size_type
// MemoryPool<T, BlockSize>::max_size() const noexcept {
//   size_type maxBlocks = -1 / BlockSize;
//   return (BlockSize - sizeof(data_pointer_)) / sizeof(slot_type_) * maxBlocks;
// }

// template <typename T, size_t BlockSize>
// template <class U, class... Args>
// inline void
// MemoryPool<T, BlockSize>::construct(U *p, Args &&... args) {
//   new (p) U(std::forward<Args>(args)...);
// }

// template <typename T, size_t BlockSize>
// template <class U>
// inline void
// MemoryPool<T, BlockSize>::destroy(U *p) {
//   p->~U();
// }

// template <typename T, size_t BlockSize>
// template <class... Args>
// inline typename MemoryPool<T, BlockSize>::pointer
// MemoryPool<T, BlockSize>::newElement(Args &&... args) {
//   pointer result = allocate();
//   construct<value_type>(result, std::forward<Args>(args)...);
//   return result;
// }

// template <typename T, size_t BlockSize>
// inline void
// MemoryPool<T, BlockSize>::deleteElement(pointer p) {
//   if (p != nullptr) {
//     p->~value_type();
//     deallocate(p);
//   }
// }

// #endif

// using namespace std;
// using namespace boost;

int main() {

  // object_pool<Demo> p1;

  // Demo * p = p1.malloc();

  // cout << p1.is_from(p) << endl;
  
  // cout << (p->a != 1) << "  " << (p->b != 2) << endl;

  // Demo * pa = p1.construct(4, 5);

  // cout << (pa->a == 4 && pa->b == 5) << endl;

  // p1.destroy(p);

  // cout << p1.is_from(p) << endl;
}